package com.fileshare.web.service.impl;

import com.fileshare.web.service.PermissionService;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

@Service("auth")
public class PermissionServiceImpl implements PermissionService {
    @Override
    public Boolean matchAll(String... permissions) {
        List<String> userPermissions = getUserPermissions();
        if (isAdmin(userPermissions)) {
            return true;
        }
        for (String permission : permissions) {
            if (!hasAuthority(permission, userPermissions)) {
                return false;
            }
        }
        return true;
    }

    @Override
    public Boolean matchDb() {
        return false;
    }

    @Override
    public Boolean matchAny(String... permissions) {
        //permission = auth[scopes]:action[qualifiers]
        // 获取当前用户的所有权限
        List<String> userPermissions = getUserPermissions();
        if (isAdmin(userPermissions)) {
            return true;
        }
        for (String permission : permissions) {
            if (hasAuthority(permission, userPermissions)) {
                return true;
            }
        }
        return false;
    }

    private boolean hasAuthority(String permission, List<String> userPermissions) {
        permission = permission.replace(" ", "");
        if (isAdmin(userPermissions)) {
            return true;
        }
        String[] permissionLimits = permission.split(":");
        for (String userPermission : userPermissions) {
            if (checkPermissionAndLimits(permissionLimits, userPermission)) {
                return true;
            }
        }
        return false;
    }

    private boolean checkPermissionAndLimits(String[] permissionLimits, String userPermission) {
        String[] userPermissionLimits = userPermission.split(":");
        boolean hasPermission = true;
        for (int i = 0; i < permissionLimits.length; i++) {
            for (int j = 0; j < userPermissionLimits.length; j++) {
                if (i == j) {
                    hasPermission = hasPermission &&
                            matchPermissionAndLimits(permissionLimits[i], userPermissionLimits[j]);
                }
            }
        }
        return hasPermission;
    }

    private boolean matchPermissionAndLimits(String permissionLimit, String userPermissionLimit) {
        if (hasLimits(permissionLimit)) {
            String auth = getPrefix(permissionLimit);
            String limits = getSuffix(permissionLimit);
            if (hasLimits(userPermissionLimit)) {
                String userAuth = getPrefix(userPermissionLimit);
                String userLimits = getSuffix(userPermissionLimit);
                return matchAuthority(auth, userAuth) && matchLimits(limits, userLimits);
            } else {
                return matchAuthority(auth, userPermissionLimit);
            }
        } else {
            return userPermissionLimit.contains(permissionLimit);
        }
    }

    private String getPrefix(String permissionLimit) {
        return permissionLimit.substring(0, permissionLimit.indexOf("["));
    }

    private String getSuffix(String permissionLimit) {
        return permissionLimit.substring(permissionLimit.indexOf("[") + 1, permissionLimit.indexOf("]"));
    }

    private boolean matchLimits(String perLimits, String userLimits) {
        boolean matchAll = !perLimits.contains("any(");
        perLimits = perLimits.replace("any(", "");
        perLimits = perLimits.replace("all(", "");
        perLimits = perLimits.replace(")", "");
        String[] limits = perLimits.split(",");
        if (matchAll) {
            for (String limit : limits) {
                if (!userLimits.contains(limit)) {
                    return false;
                }
            }
            return true;
        } else {
            for (String limit : limits) {
                if (userLimits.contains(limit)) {
                    return true;
                }
            }
        }
        return false;
    }

    private boolean matchAuthority(String auth, String userAuth) {
        if (auth.contains("|")) {
            for (String split : auth.split("\\|")) {
                if (userAuth.equals(split)) {
                    return true;
                }
            }
        } else {
            return userAuth.equals(auth);
        }
        return false;
    }

    private boolean hasLimits(String permissionLimit) {
        return permissionLimit.contains("[") && permissionLimit.contains("]");
    }

    private List<String> getUserPermissions() {
        Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
        List<String> userPermissions = new ArrayList<>();
        if (authentication != null) {
            userPermissions = authentication.getAuthorities()
                    .stream()
                    .map(GrantedAuthority::getAuthority)
                    .collect(Collectors.toList());
        }
        return userPermissions;
    }

    private boolean isAdmin(List<String> userPermissions) {
        return userPermissions.stream().anyMatch(permission -> permission.contains("administrator"));
    }
}
